#include "PayLogicMgr.h"
#include "LogicService.h"
#include "ProtoBuffer/ServerInternalCmd.pb.h"
#include "ProtoBuffer/ClientToServerCmd.pb.h"
#include "ProtoBuffer/ServerToClientCmd.pb.h"
#include "ProtoBuffer/Pay.pb.h"
#include "Character/CreatureMgr.h"
#include "Character/PayPart.h"
#include "Character/Player.h"

PayLogicMgr::PayLogicMgr():
m_pYkConfig(nullptr),
m_nextZeroTime(0)
{
}

PayLogicMgr::~PayLogicMgr()
{}

bool PayLogicMgr::Init()
{
	bool result = false;
	bool retCode = false;
	RechargeRechargeCfgMap::const_iterator iter, iterEnd;
	std::unordered_map<std::string, const RechargeRechargeCfgInfo*>::iterator findIter;
	const RechargeRechargeCfgMap* pRecharMap = nullptr;
	m_channPayOpenMap.clear();
	m_productCfgMap.clear();

	IMessageDispatch *pMessageDispatch = g_GetLogicService()->GetServiceMessageDispatch();
	MMOLOG_PROCESS_ERROR(pMessageDispatch != nullptr);

	retCode = pMessageDispatch->registerServerHandler(EMODULE_ID_PAY, this);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = pMessageDispatch->registerDBProxyHandler(EMODULE_ID_PAY, this);
	MMOLOG_PROCESS_ERROR(retCode);

	pRecharMap = g_GetRechargeRechargeCfgTable()->GetRechargeRechargeCfgMap();
	MMOLOG_PROCESS_ERROR(pRecharMap != nullptr);

	iter = pRecharMap->begin();
	iterEnd = pRecharMap->end();
	for (; iter != iterEnd; iter++)
	{
		//默认的每个产品id都必须不一样
		findIter = m_productCfgMap.find(iter->second.defaultPoint);
		if (m_productCfgMap.end() != findIter)
			MMO_ASSERT(true);
		m_productCfgMap[iter->second.defaultPoint] = &iter->second;

		for (size_t i = 0; i < iter->second.vecRechargeRechargeChannelCfg.size(); i++)
		{
			const RechargeRechargeChannelCfgInfo& channCfg = iter->second.vecRechargeRechargeChannelCfg[i];
			PRODUCT_MAP& productmap = m_channProductCfgMap[channCfg.id];
			findIter = productmap.find(channCfg.point);
			if (productmap.end() != findIter)
				MMO_ASSERT(true);
			productmap[channCfg.point] = &iter->second;
		}

		if (iter->second.type == Yk_Pay)
			m_pYkConfig = &iter->second;
	}

	result = true;
Exit0:
	return result;

	return true;
}

bool PayLogicMgr::UnInit()
{
    bool result = false;
    bool retCode = false;
	IMessageDispatch *pMessageDispatch = g_GetLogicService()->GetServiceMessageDispatch();
	MMOLOG_PROCESS_ERROR(pMessageDispatch != nullptr);

	retCode = pMessageDispatch->unregisterServerHandler(EMODULE_ID_PAY);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = pMessageDispatch->unregisterDBProxyHandler(EMODULE_ID_PAY);
	MMOLOG_PROCESS_ERROR(retCode);

	m_productCfgMap.clear();

    result = true;
Exit0:
	return result;
}

bool PayLogicMgr::GetPayFuncOpen(uint32_t channId)
{
	std::unordered_map<uint32_t, bool>::iterator iter = m_channPayOpenMap.find(channId);
	std::unordered_map<uint32_t, bool>::iterator iterEnd = m_channPayOpenMap.end();
	if (iter != iterEnd)
		return iter->second;

	LogErrFmtPrint("PayLogicMgr::GetPayFuncOpen, cannt find pay open channid:%d ", channId);
	return true;
}

void PayLogicMgr::GetProductIndexs(uint32_t channid, REPEATED_UINT32* indexs)
{
	if (indexs == nullptr)
		return;

	std::unordered_map<uint32_t, REPEATED_UINT32>::iterator iter = m_productIndexs.find(channid);
	std::unordered_map<uint32_t, REPEATED_UINT32>::iterator iterEnd = m_productIndexs.end();
	if (iter != iterEnd)
		indexs->CopyFrom(iter->second);
}

uint64_t PayLogicMgr::GetNextZeroTime()
{
	uint64_t curT = ServerTime::UnixSec();
	if (curT > m_nextZeroTime)
	{
		m_nextZeroTime = Time::GetZeroTime(curT) + ServerTime::DayTotalSec();
	}
	return m_nextZeroTime;
}

void PayLogicMgr::onServerMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	switch (actionId)
	{
	case CENTER_TO_LOGIC_PAY_CURRENCY_REQ:
		CurrencyReqFromLogic(package);
		break;
	case CENTER_TO_LOGIC_UPDATE_OTHER_PAY:
	default:
		break;
	}
}

void PayLogicMgr::onDBProxyMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	if (actionId == DBPROXY_PROTOCOL_READ_PAY_INFO_RSP)
	{
		CurrencyReqFromDB(package);
	}
	else
	{
		LogErrFmtPrint("PayLogicMgr::onDBProxyMessage recv wrong cmd:%d", actionId);
	}
}

bool PayLogicMgr::CurrencyReqFromLogic(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;
	const RechargeRechargeCfgInfo *precharge = nullptr;

	PayInfo* payinfo = nullptr;
	CurrencyLogic clReq;
	Player* pPlayer = nullptr;

	retCode = clReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	payinfo = clReq.mutable_payinfo();
	MMOLOG_PROCESS_ERROR(payinfo);

	precharge = GetRechargeCfg(payinfo->channid(), payinfo->productid());
	if (precharge == nullptr)
	{
		LogErrFmtPrint("PayLogicMgr::CurrencyReq, precharge == null, cid:%lu, productid:%s, money:%d", payinfo->cid(), payinfo->productid().c_str(), payinfo->money());
		MMOLOG_PROCESS_ERROR(false);
	}

	pPlayer = g_GetCreatureMgr()->GetNoScenePlayer(payinfo->cid());
	if (pPlayer == nullptr || pPlayer->GetAccountState() == ACCOUNT_GAME_STATE_SWITCH)
	{
		//PayDebugLog(&payinfo, "逻辑服不在线，存db");
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_PAY, CENTER_TO_LOGIC_PAY_CURRENCY_FAIL, &clReq);
	}
	else
	{
		PayPart* pPart = static_cast<PayPart*>(pPlayer->GetPart(PART_PAY));
		if (pPart == nullptr)
		{
			LogErrFmtPrint("PayLogicMgr::CurrencyReq, pPart == null, cid:%lu, order:%s", payinfo->cid(), payinfo->order().c_str());
			MMOLOG_PROCESS_ERROR(false);
		}
		pPart->PayCurrency(precharge, *payinfo);

		PayDebugLog(payinfo, "充值道具发放成功");
		if (!payinfo->fakepay())
			pPlayer->PayLog(payinfo->productid(), payinfo->order(), precharge->price, precharge->quantity, 0);
	}


    result = true;
Exit0:
	return result;
}

bool PayLogicMgr::CurrencyReqFromDB(RECV_PACKAGE& package)
{
	bool result = false;
	bool retCode = false;
	const RechargeRechargeCfgInfo *precharge = nullptr;

	LoadPayInfoRsp loadPayRsp;
	PayInfo* payinfo = nullptr;
	PayInfo* dbPayInfo = nullptr;
	PayPart* pPart = nullptr;
	Player* pPlayer = nullptr;
	uint32_t firstDiamond = 0;
	uint32_t maxDBid = 0;

	UpdatePayInfoToDB updatePayInfo;

	retCode = loadPayRsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	MMOLOG_PROCESS_ERROR(loadPayRsp.pays_size() > 0);

	pPlayer = g_GetCreatureMgr()->GetNoScenePlayer(loadPayRsp.cid());
	if (pPlayer == nullptr )
	{
		LogErrFmtPrint("PayLogicMgr::CurrencyReqFromDB, pPart == null, cid:%lu", loadPayRsp.cid());
		MMOLOG_PROCESS_ERROR(false);
	}

	if (pPlayer->GetAccountState() == ACCOUNT_GAME_STATE_SWITCH)
	{
		LogErrFmtPrint("PayLogicMgr::CurrencyReqFromDB,pPlayer->GetAccountState() == ACCOUNT_GAME_STATE_SWITCH, cid:%lu", loadPayRsp.cid());
		MMOLOG_PROCESS_ERROR(false);
	}

	pPart = static_cast<PayPart*>(pPlayer->GetPart(PART_PAY));
	if (pPart == nullptr)
	{
		LogErrFmtPrint("PayLogicMgr::CurrencyReq, pPart == null, cid:%lu", loadPayRsp.cid());
		MMOLOG_PROCESS_ERROR(false);
	}

	maxDBid = pPart->GetMaxPayId();
	for (int i = 0; i < loadPayRsp.pays_size(); i++)
	{
		payinfo = loadPayRsp.mutable_pays(i);
		if (payinfo == nullptr)
		{
			LogErrPrint("PayLogicMgr::CurrencyReqFromDB payinfo == null");
			continue;
		}

		if (payinfo->dbid() <= maxDBid)
		{
			LogErrFmtPrint("PayLogicMgr::CurrencyReq, id < maxDBid, cid:%lu, order:%s, money:%d, id:%d, dbid:%d", payinfo->cid(), payinfo->order().c_str(), payinfo->money(), maxDBid, payinfo->dbid());
			continue;
		}
		precharge = GetRechargeCfg(payinfo->channid(), payinfo->productid());
		if (precharge == nullptr)
		{
			LogErrFmtPrint("PayLogicMgr::CurrencyReq, precharge == null, cid:%lu, order:%s, money:%d", payinfo->cid(), payinfo->order().c_str(), payinfo->money());
			continue;
		}

		//设置角色最大dbid防止离线支付重复发送
		maxDBid = payinfo->dbid();
		pPart->SetMaxPayId(maxDBid);
		firstDiamond = pPart->PayCurrency(precharge, *payinfo);

		PayDebugLog(payinfo, "充值道具发放成功");
		if (!payinfo->fakepay())
			pPlayer->PayLog(payinfo->productid(), payinfo->order(), precharge->price, precharge->quantity, firstDiamond);

		dbPayInfo = updatePayInfo.add_pays();
		if (dbPayInfo == nullptr)
		{
			LogErrFmtPrint("PayLogicMgr::CurrencyReq, dbpayinfo == null, cid:%lu", loadPayRsp.cid());
			continue;
		}
		dbPayInfo->CopyFrom(*payinfo);
	}

	retCode = g_GetLogicService()->SendDataToDBProxy(EMODULE_ID_PAY, DBPROXY_PROTOCOL_UPDATE_PAY_INFO, &updatePayInfo);
	MMOLOG_PROCESS_ERROR(retCode);

	result = true;
Exit0:
	return result;
}

bool PayLogicMgr::OtherPayInfoFromCenter(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;

	UpdatePayToLogic updatePay;
	retCode = updatePay.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	m_productIndexs.clear();
	m_channPayOpenMap.clear();

	for (int i = 0; i < updatePay.indexs_size(); i++)
	{
		const UpdatePayToLogic::ChannPayIndex& pi = updatePay.indexs(i);
		m_productIndexs[pi.channid()] = pi.indexs();
	}

	for (int j = 0; j < updatePay.payopens_size(); j++)
	{
		const UpdatePayToLogic::ChannPayOpen& po = updatePay.payopens(j);
		m_channPayOpenMap[po.channid()] = po.open();
	}

    result = true;
Exit0:
	return result;
}

void PayLogicMgr::PayDebugLog(PayInfo* payInfo, std::string describe /* = "" */)
{
	rapidjson::Document doc;
	JsonObject obj(&doc);
	obj.AddUInt32("tid", TID_PAY_DEBUG);
	obj.AddUInt64("cid", payInfo->cid());
	obj.AddUInt32("uid", payInfo->uid());
	obj.AddString("product", payInfo->productid());
	obj.AddString("order", payInfo->order());
	obj.AddUInt32("money", payInfo->money());
	obj.AddString("describe", describe);
	obj.AddString("myoder", payInfo->myorder());

	bool bsuc = g_GetLogicService()->SendLogToLogServer(obj);
	if (bsuc == false)
		LogErrFmtPrint("player paylog error, cid:%lu, uid:%d", payInfo->cid(),payInfo->uid());
}

const RechargeRechargeCfgInfo* PayLogicMgr::GetRechargeCfg(uint32_t channId, string productId)
{
		CHANN_PRODUCT_MAP::iterator iter = m_channProductCfgMap.find(channId);
		if (iter != m_channProductCfgMap.end())
		{
			PRODUCT_MAP::iterator findIter = iter->second.find(productId);
			if (findIter != iter->second.end())
				return findIter->second;
		}
		else
		{
			PRODUCT_MAP::iterator findIter = m_productCfgMap.find(productId);
			if (findIter != m_productCfgMap.end())
				return findIter->second;
		}

		return nullptr;
}

void PayLogicMgr::OfflinePayInfoReq(uint64_t cid)
{
	LoadPayInfoReq  loadReq;
	loadReq.set_cid(cid);

	if (!g_GetLogicService()->SendDataToDBProxy(EMODULE_ID_PAY, DBPROXY_PROTOCOL_READ_PAY_INFO_REQ, &loadReq))
		LogErrLogFmtPrint("PayLogicMgr::OfflinePayInfoReq fail cid:%lu", cid);
}

/*
bool PayLogicMgr::CdKeyReq(uint64_t cid, string cdKey)
{
	Player* pPlayer = nullptr; 
	LogicCdkeyReq cdkeyReq;

    bool result = false;
    bool retCode = false;

	pPlayer = g_GetCreatureMgr()->GetNoScenePlayer(cid);
	MMOLOG_PROCESS_ERROR(pPlayer != nullptr);
	MMOLOG_PROCESS_ERROR(cdKey.size() >= 10);

	cdkeyReq.set_cid(pPlayer->GetCid());
	cdkeyReq.set_uid(pPlayer->GetUid());
	cdkeyReq.set_channid(pPlayer->GetChannId());
	cdkeyReq.set_zid(g_GetLogicService()->GetZID());
	cdkeyReq.set_cdkey(cdKey);

	retCode = g_GetLogicService()->SendDataToCenter(EMODULE_ID_RECV_ZONE_MSG, LOGIC_TO_WEBOP_CDKEY_REQ, &cdkeyReq);
	MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
	return result;
}

bool PayLogicMgr::CdKeyResult(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;
	LogicCdKeyRsp rsp;
	retCode = rsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	LogDebugFmtPrint("ckd result:%lu  result%d", rsp.cid(), rsp.retcode());
    result = true;
Exit0:
	return result;
}

*/